package com.environment.viewer;

import java.awt.Font;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.JFileChooser;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileNameExtensionFilter;

import com.environment.Environment;
import com.environment.component.AstronomyComponent;
import com.environment.component.EffectComponent;
import com.environment.component.SkyComponent;
import com.environment.component.WeatherComponent;
import com.environment.component.enumn.ESkyPart;
import com.environment.component.enumn.EWeather;
import com.jme.app.SimplePassGame;
import com.jme.image.Texture;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.RenderPass;
import com.jme.util.TextureManager;

/**
 * <code>EnvironmentViewer</code> allows user to choose textures and preview
 * them with the environment system.
 * 
 * @author Yi Wang (Neakor)
 * @version Creation date: 08-01-2008 10:44 EST
 * @version Modified date: 08-07-2008 10:44 EST
 */
public class EnvironmentViewer extends SimplePassGame {
	/**
	 * The <code>JFileChooser</code> instance.
	 */
	private JFileChooser chooser;
	/**
	 * The day sky texture <code>URL</code>.
	 */
	private URL daySky;
	/**
	 * The night sky texture <code>URL</code>.
	 */
	private URL nightSky;
	/**
	 * The day cloud texture <code>URL</code>.
	 */
	private URL dayCloud;
	/**
	 * The night cloud texture <code>URL</code>.
	 */
	private URL nightCloud;
	/**
	 * The array of four lens flare textures <code>URL</code>.
	 */
	private URL[] flares;
	/**
	 * The sun texture <code>URL</code>.
	 */
	private URL sun;
	/**
	 * The moon texture <code>URL</code>.
	 */
	private URL moon;
	/**
	 * The up texture <code>URL</code> of the sky box.
	 */
	private URL starsUp;
	/**
	 * The down texture <code>URL</code> of the sky box.
	 */
	private URL starsDown;
	/**
	 * The north texture <code>URL</code> of the sky box.
	 */
	private URL starsNorth;
	/**
	 * The south texture <code>URL</code> of the sky box.
	 */
	private URL starsSouth;
	/**
	 * The east texture <code>URL</code> of the sky box.
	 */
	private URL starsEast;
	/**
	 * The west texture <code>URL</code> of the sky box.
	 */
	private URL starsWest;
	/**
	 * The rain texture <code>URL</code>.
	 */
	private URL rain;
	/**
	 * The snow texture <code>URL</code>.
	 */
	private URL snow;
	private Environment environment;
	private SkyComponent sky;
	private EffectComponent effects;
	private AstronomyComponent astronomy;
	private WeatherComponent weather;

	/**
	 * Main method.
	 */
	public static void main(String[] args) {
		EnvironmentViewer preview = new EnvironmentViewer();
		preview.setConfigShowMode(ConfigShowMode.AlwaysShow);
		preview.initURLs();
		preview.start();
	}
	
	/**
	 * Constructor of <code>EnvironmentPreview</code>.
	 */
	public EnvironmentViewer() {
		this.initTheme();
		this.initChooser();
	}
	
	/**
	 * Initialize the Swing theme.
	 */
	private void initTheme() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
		UIManager.put("Button.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ToggleButton.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("RadioButton.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("CheckBox.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ColorChooser.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ComboBox.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Label.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("List.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("MenuBar.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("MenuItem.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("RadioButtonMenuItem.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("CheckBoxMenuItem.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Menu.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("PopupMenu.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("OptionPane.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Panel.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ProgressBar.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ScrollPane.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Viewport.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TabbedPane.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Table.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TableHeader.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TextField.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("PasswordField.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TextArea.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TextPane.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("EditorPane.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("TitledBorder.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ToolBar.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("ToolTip.font", new Font("Tohama",Font.PLAIN,11));
		UIManager.put("Tree.font", new Font("Tohama",Font.PLAIN,11));
	}
	
	/**
	 * Initialize the file chooser. 
	 */
	private void initChooser() {
		this.chooser = new JFileChooser();
		FileNameExtensionFilter filter = new FileNameExtensionFilter("Texture", new String[]{"tga", "jpg", "bmp", "png"});
		this.chooser.setFileFilter(filter);
	}
	
	/**
	 * Initialze all the <code>URL</code>.
	 */
	private void initURLs() {
		this.daySky = this.loadURL("Day sky texture");
		this.nightSky = this.loadURL("Night sky texture");
		this.dayCloud = this.loadURL("Day cloud texture");
		this.nightCloud = this.loadURL("Night cloud texture");
		this.flares = new URL[4];
		this.flares[0] = this.loadURL("Lens flare texture 1");
		this.flares[1] = this.loadURL("Lens flare texture 2");
		this.flares[2] = this.loadURL("Lens flare texture 3");
		this.flares[3] = this.loadURL("Lens flare texture 4");
		this.sun = this.loadURL("Sun texture");
		this.moon = this.loadURL("Moon texture");
		this.starsUp = this.loadURL("Up star texture");
		this.starsDown = this.loadURL("Down star texture");
		this.starsNorth = this.loadURL("North star texture");
		this.starsSouth = this.loadURL("South star texture");
		this.starsEast = this.loadURL("East star texture");
		this.starsWest = this.loadURL("West star texture");
		this.rain = this.loadURL("Rain texture");
		this.snow = this.loadURL("Snow texture");
	}
	
	/**
	 * Load a texture <code>URL</code>.
	 * @return The loaded texture <code>URL</code>.
	 */
	private URL loadURL(String promt) {
		this.chooser.setDialogTitle(promt);
		int value = chooser.showOpenDialog(null);
		if (value != JFileChooser.APPROVE_OPTION) return null;
		try {
			return chooser.getSelectedFile().toURI().toURL();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	protected void simpleInitGame() {
		this.setupKeys();
		this.buildRootPass();
		this.buildEnvironment();
	}
	
	/**
	 * Setup rain and snow triggers.
	 */
	private void setupKeys() {
    	this.input.setActionSpeed(20);
		KeyBindingManager.getKeyBindingManager().add("rain", KeyInput.KEY_I);
		KeyBindingManager.getKeyBindingManager().add("snow", KeyInput.KEY_O);
		KeyBindingManager.getKeyBindingManager().add("clear", KeyInput.KEY_M);
	}

	/**
	 * Build the root render pass.
	 */
	private void buildRootPass() {
		RenderPass rootPass = new RenderPass();
		rootPass.add(this.rootNode);
		this.pManager.add(rootPass);
    }
	
	/**
	 * Build the environment.
	 */
	private void buildEnvironment() {
		this.environment = new Environment();
		this.sky = new SkyComponent();
		this.effects = new EffectComponent();
		this.astronomy = new AstronomyComponent();
		this.weather = new WeatherComponent();
		this.buildConnection();
		this.buildSkyComponent();
		this.buildEffectComponent();
		this.buildAstronomyComponent();
		this.buildWeatherComponent();
		this.environment.connect(this.sky);
		this.environment.connect(this.effects);
		this.environment.connect(this.astronomy);
		this.environment.connect(this.weather);
		this.environment.setCurrentTime("17.00");
		this.environment.applyToScene(this.rootNode, this.pManager);
	}
	
	/**
	 * Establish essential connections.
	 */
	private void buildConnection() {
		this.astronomy.connect(this.sky);
		this.astronomy.connect(this.effects);
	}
	
	/**
	 * Build sky component.
	 */
	private void buildSkyComponent() {
		this.sky.setUseSphere(false);
		this.sky.setSkyRadius(500);
		this.sky.setRotationCycle(100);
		this.sky.setTexture(ESkyPart.DaySky, this.loadTexture(this.daySky));
		this.sky.setTexture(ESkyPart.NightSky, this.loadTexture(this.nightSky));
		this.sky.setTexture(ESkyPart.UpperDayCloud, this.loadTexture(this.dayCloud));
		this.sky.setTexture(ESkyPart.UpperNightCloud, this.loadTexture(this.nightCloud));
	}
	
	/**
	 * Build effect component.
	 */
	private void buildEffectComponent() {
		Texture[] flares = new Texture[4];
		flares[0] = this.loadTexture(this.flares[0]);
		flares[1] = this.loadTexture(this.flares[1]);
		flares[2] = this.loadTexture(this.flares[2]);
		flares[3] = this.loadTexture(this.flares[3]);
		this.effects.setFlareTextures(flares);
	}
	
	/**
	 * Build astronomy component.
	 */
	private void buildAstronomyComponent() {
		this.astronomy.setLengthOfDar(50);
		this.astronomy.setDawnColor(new ColorRGBA(0.9843f, 0.5098f, 0f, 1f));
		this.astronomy.setMoonColor(new ColorRGBA(0.2745f,0.4961f,0.8196f,1f));
		this.astronomy.setSunTexture(this.loadTexture(this.sun));
		this.astronomy.setMoonTexture(this.loadTexture(this.moon));
		Texture[] textures = new Texture[6];
		textures[0] = this.loadTexture(this.starsUp);
		textures[1] = this.loadTexture(this.starsNorth);
		textures[2] = this.loadTexture(this.starsEast);
		textures[3] = this.loadTexture(this.starsSouth);
		textures[4] = this.loadTexture(this.starsWest);
		textures[5] = this.loadTexture(this.starsDown);
		this.astronomy.setStarTextures(textures);
	}
	
	/**
	 * Build weather component.
	 */
	private void buildWeatherComponent() {
		this.weather.setRainTexture(this.loadTexture(this.rain));
		this.weather.setSnowTexture(this.loadTexture(this.snow));
	}
	
	/**
	 * Load the texture pointed by given URL.
	 * @param url The <code>URL</code> to the texture.
	 * @return The <code>Texture</code> instance.
	 */
	private Texture loadTexture(URL url) {
		return TextureManager.loadTexture(url, Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
	}

	@Override
	protected void simpleUpdate() {
		this.environment.update(this.tpf);
		if(KeyBindingManager.getKeyBindingManager().isValidCommand("rain", false)) {
			this.environment.setWeather(EWeather.Rain, this.rootNode);
		} else if (KeyBindingManager.getKeyBindingManager().isValidCommand("snow", false)) {
			this.environment.setWeather(EWeather.Snow, this.rootNode);
        } else if(KeyBindingManager.getKeyBindingManager().isValidCommand("clear", false)) {
        	this.environment.setWeather(EWeather.Sunny, this.rootNode);
        }
	}
}
